<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webaudio - orientation</title>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<link type="text/css" rel="stylesheet" href="main.css">
	</head>
<body>

	<audio loop id="music" preload="auto" style="display: none">
		<source src="sounds/376737_Skullbeatz___Bad_Cat_Maste.ogg" type="audio/ogg">
		<source src="sounds/376737_Skullbeatz___Bad_Cat_Maste.mp3" type="audio/mpeg">
	</audio>

	<div id="overlay">
		<button id="startButton">Play</button>
	</div>
	<div id="container"></div>
	<div id="info">
		<a href="https://threejs.org" target="_blank" rel="noopener noreferrer">three.js</a> webaudio - orientation<br/>
		music by <a href="http://www.newgrounds.com/audio/listen/376737" target="_blank" rel="noopener noreferrer">skullbeatz</a>
	</div>

	<!-- Import maps polyfill -->
	<!-- Remove this when import maps will be widely supported -->
	<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>

	<script type="importmap">
		{
			"imports": {
				"three": "../build/three.module.js",
				"three/addons/": "./jsm/"
			}
		}
	</script>

	<script type="module">
		import * as THREE from 'three';

		import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
		import { PositionalAudioHelper } from 'three/addons/helpers/PositionalAudioHelper.js';
		import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

		let scene, camera, renderer;

		const startButton = document.getElementById( 'startButton' );
		startButton.addEventListener( 'click', init );

		function init() {

			const overlay = document.getElementById( 'overlay' );
			overlay.remove();

			const container = document.getElementById( 'container' );

			//

			camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 100 );
			camera.position.set( 3, 2, 3 );

			const reflectionCube = new THREE.CubeTextureLoader()
				.setPath( 'textures/cube/SwedishRoyalCastle/' )
				.load( [ 'px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg' ] );

			scene = new THREE.Scene();
			scene.background = new THREE.Color( 0xa0a0a0 );
			scene.fog = new THREE.Fog( 0xa0a0a0, 2, 20 );

			//

			const hemiLight = new THREE.HemisphereLight( 0xffffff, 0x444444 );
			hemiLight.position.set( 0, 20, 0 );
			scene.add( hemiLight );

			const dirLight = new THREE.DirectionalLight( 0xffffff );
			dirLight.position.set( 5, 5, 0 );
			dirLight.castShadow = true;
			dirLight.shadow.camera.top = 1;
			dirLight.shadow.camera.bottom = - 1;
			dirLight.shadow.camera.left = - 1;
			dirLight.shadow.camera.right = 1;
			dirLight.shadow.camera.near = 0.1;
			dirLight.shadow.camera.far = 20;
			scene.add( dirLight );

			// scene.add( new THREE.CameraHelper( dirLight.shadow.camera ) );

			//

			const mesh = new THREE.Mesh( new THREE.PlaneGeometry( 50, 50 ), new THREE.MeshPhongMaterial( { color: 0x999999, depthWrite: false } ) );
			mesh.rotation.x = - Math.PI / 2;
			mesh.receiveShadow = true;
			scene.add( mesh );

			const grid = new THREE.GridHelper( 50, 50, 0x888888, 0x888888 );
			scene.add( grid );

			//

			const listener = new THREE.AudioListener();
			camera.add( listener );

			const audioElement = document.getElementById( 'music' );
			audioElement.play();

			const positionalAudio = new THREE.PositionalAudio( listener );
			positionalAudio.setMediaElementSource( audioElement );
			positionalAudio.setRefDistance( 1 );
			positionalAudio.setDirectionalCone( 180, 230, 0.1 );

			const helper = new PositionalAudioHelper( positionalAudio, 0.1 );
			positionalAudio.add( helper );

			//

			const gltfLoader = new GLTFLoader();
			gltfLoader.load( 'models/gltf/BoomBox.glb', function ( gltf ) {

				const boomBox = gltf.scene;
				boomBox.position.set( 0, 0.2, 0 );
				boomBox.scale.set( 20, 20, 20 );

				boomBox.traverse( function ( object ) {

					if ( object.isMesh ) {

						object.material.envMap = reflectionCube;
						object.geometry.rotateY( - Math.PI );
						object.castShadow = true;

					}

				} );

				boomBox.add( positionalAudio );
				scene.add( boomBox );
				animate();

			} );

			// sound is damped behind this wall

			const wallGeometry = new THREE.BoxGeometry( 2, 1, 0.1 );
			const wallMaterial = new THREE.MeshBasicMaterial( { color: 0xff0000, transparent: true, opacity: 0.5 } );

			const wall = new THREE.Mesh( wallGeometry, wallMaterial );
			wall.position.set( 0, 0.5, - 0.5 );
			scene.add( wall );


			//

			renderer = new THREE.WebGLRenderer( { antialias: true } );
			renderer.setSize( window.innerWidth, window.innerHeight );
			renderer.setPixelRatio( window.devicePixelRatio );
			renderer.outputEncoding = THREE.sRGBEncoding;
			renderer.shadowMap.enabled = true;
			container.appendChild( renderer.domElement );

			//

			const controls = new OrbitControls( camera, renderer.domElement );
			controls.target.set( 0, 0.1, 0 );
			controls.update();
			controls.minDistance = 0.5;
			controls.maxDistance = 10;
			controls.maxPolarAngle = 0.5 * Math.PI;

			//

			window.addEventListener( 'resize', onWindowResize );

		}

		function onWindowResize() {

			camera.aspect = window.innerWidth / window.innerHeight;
			camera.updateProjectionMatrix();

			renderer.setSize( window.innerWidth, window.innerHeight );

		}

		function animate() {

			requestAnimationFrame( animate );
			renderer.render( scene, camera );

		}

	</script>

</body>
</html>
